﻿using System.IO;
using System.Collections.Generic;

namespace Game.Lib.CSG
{
    public class Plane : Shape3D
    {
        public override List<Vector> CriticalPoints
        {
            get
            {
                List<Vector> ret = new List<Vector>(1);
                ret.Add(Pos);
                return ret;
            }
        }
        public override Vector3 Size
        {
            get
            {
                return new Vector3(_Size, 0f);
            }
            set
            {
                _Size = new Vector2(value.X, value.Y);
            }
        }

        public override float SurfaceArea
        {
            get { return 2f * Size.X * Size.Y; }
        }

        public override float Volume
        {
            get { return 0f; }
        }

        public Vector3 Normal
        {
            get
            {
                return Vector3.ZAxis * Rot;
            }
            set
            {
                Rot = Vector3.RotationBetween(Vector3.ZAxis, value);
            }
        }

        private Vector2 _Size;

        public Plane()
        {
            Pos = Vector3.Zero;
            Rot = Quaternion.Zero;
            _Size = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
        }

        public Plane(Vector3 pos, Vector3 norm)
        {
            Pos = pos;
            Normal = norm;
            _Size = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
        }

        public Plane(Vector3 pos, Quaternion rot)
        {
            Pos = pos;
            Rot = rot;
            _Size = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
        }

        public Plane(Vector3 pos, Vector3 norm, Vector2 size)
            : this(pos, norm)
        {
            _Size = size;
        }

        public Plane(Vector3 pos, Quaternion rot, Vector2 size)
            : this(pos, rot)
        {
            _Size = size;
        }

        public Plane(Vector3 pos, Vector3 norm, float ext) : this(pos, norm, new Vector2(ext)) { }

        public Plane(Vector3 pos, Quaternion rot, float ext) : this(pos, rot, new Vector2(ext)) { }

        public override AABB GetBoundingBox()
        {
            return new AABB(Pos, Size * Rot); //TODO: test if that code works
        }

        public override Ellipsoid GetBoundingSphere()
        {
            return new Ellipsoid(Pos, Size.Magnitude() * .5f);
        }

        public override bool Inside(Vector3 pos)
        {
            return (pos - Pos) * Normal < Utils.Epsilon;
        }

        public override Intersection RayCast(Ray r)
        {
            float num = (Pos - r.Start) * Normal;
            if (num == 0f) return Intersection.Missed;
            float denom = r.Direction * Normal;
            float dist = num / denom;
            if (dist <= 0f) return Intersection.Missed;
            Vector3 pos = r.Get(dist);
            if (!Inside(pos)) return Intersection.Missed;
            return new Intersection(r, dist, Normal);
        }

        public Vector3 Get(Vector2 pos)
        {
            return new Vector3(pos, 0f) * Rot;
        }

        public override void Serialize(Stream s)
        {
            Pos.Serialize(s);
            _Size.Serialize(s);
            Normal.Serialize(s);
        }

        public override void Deserialize(Stream s)
        {
            Pos.Deserialize(s);
            _Size.Deserialize(s);
            Normal.Deserialize(s);
        }
    }
}
